// Shader Material Resource
// (c) jimon game studio

#ifndef JEH_JESHADERMATERIALRESOURCE
#define JEH_JESHADERMATERIALRESOURCE

#include "IResourceManager.h"
#include "jeSharedResource.h"
#include "IRender.h"

namespace je
{
	namespace media
	{
		//! Shader Material Resource
		class jeShaderMaterialResource:public je::media::IResource
		{
		public:
			typedef jeSharedResourceManagerUniversal jeSharedShaderMaterialResourceManager;
		protected:
			core::IBuffer * ShaderMaterial;
			jeSharedShaderMaterialResourceManager * SharedManager;
		public:
			//! Constructor
			jeShaderMaterialResource(const jeStringc & ResourceName)
				:IResource(ResourceName),ShaderMaterial(NULL)
			{
				JENEW(SharedManager,jeSharedShaderMaterialResourceManager)
			}

			//! Constructor
			jeShaderMaterialResource(const jeStringc & ResourceName,core::IBuffer * NewShaderMaterial)
				:IResource(ResourceName,false),ShaderMaterial(NewShaderMaterial)
			{
				ShaderMaterial->Grab();
				JENEW(SharedManager,jeSharedShaderMaterialResourceManager)
			}

			//! Destructor
			~jeShaderMaterialResource()
			{
				JEDELETE(SharedManager)
				if(ShaderMaterial)
					ShaderMaterial->Drop();
			}

			//! Get Shared Manager
			jeSharedShaderMaterialResourceManager * GetSharedManager()
			{
				return SharedManager;
			}

			//! Get ShaderMaterial
			core::IBuffer * GetShaderMaterial()
			{
				return ShaderMaterial;
			}

			//! Load Resource
			void Load()
			{
				core::IDataBase_Query * Query = GetResourceManager()->GetDataBase()->Query(jeStringc("SELECT * FROM ShaderMaterialResources WHERE Name = '")+CurrentResourceName+jeStringc("'"));
				ShaderMaterial = Query->GetFieldBuffer("Data");
				Query->Drop();
			}

			//! UnLoad Resource
			void UnLoad()
			{
				ShaderMaterial->Drop();
				ShaderMaterial = NULL;
			}

			//! Get Type Name
			virtual jeStringc GetTypeName()
			{
				return jeStringc("ShaderMaterialResource");
			}
		};

		//! Shader Material Resource Factory
		class jeShaderMaterialResourceFactory:public je::media::IResourceFactory
		{
		protected:
			typedef jeMap<jeStringc,jeShaderMaterialResource*> ShaderMaterialMapType;
			ShaderMaterialMapType ShaderMaterialMap;
		public:

			//! Constructor
			jeShaderMaterialResourceFactory()
			{
			}

			//! Destructor
			~jeShaderMaterialResourceFactory()
			{
				ClearResources();
			}

			//! Add Resources
			void AddResources(IResource * Resource)
			{
				ShaderMaterialMap.set(Resource->GetName(),static_cast<jeShaderMaterialResource*>(Resource));
				Resource->Grab();
			}

			//! Load Resources
			void LoadResources()
			{
				ClearResources();

				core::IDataBase_Query * Query = GetResourceManager()->GetDataBase()->Query("SELECT * FROM ShaderMaterialResources");
				while(!Query->Eof())
				{
					jeStringc ResourceName = Query->GetFieldjeStringc("Name");
					jeShaderMaterialResource * ShaderMaterialResource = NULL;
					JENEW(ShaderMaterialResource,jeShaderMaterialResource(ResourceName))
					ShaderMaterialMap.set(ResourceName,ShaderMaterialResource);
					Query->NextRow();
				}
				Query->Drop();
			}

			//! Clear Resources
			void ClearResources()
			{
				for(ShaderMaterialMapType::Iterator Iter = ShaderMaterialMap.getIterator();!Iter.atEnd();Iter++)
					Iter->getValue()->Drop();
				ShaderMaterialMap.clear();
			}

			//! Return Resource
			IResource * GetResource(const jeStringc & ResourceName)
			{
				ShaderMaterialMapType::Node * Node = ShaderMaterialMap.find(ResourceName);
				if(Node)
					return Node->getValue();
				else
					return NULL;
			}

			//! Return Resource Type
			jeStringc GetResourceType()
			{
				return jeStringc("ShaderMaterialResource");
			}

			//! Garbage Collector
			void GarbageCollector()
			{
				for(ShaderMaterialMapType::Iterator Iter = ShaderMaterialMap.getIterator();!Iter.atEnd();Iter++)
					if(Iter->getValue()->IsNeedToUnload())
						Iter->getValue()->GarbageUnload();
			}
		};

		//! Shared Shader Material
		class jeSharedShaderMaterial:public media::ISharedResource
		{
		protected:
			jeStringc ShaderMaterialResourceName;
			video::IShaderMaterial * ShaderMaterial;
		public:
			//! Constructor
			jeSharedShaderMaterial(jeShaderMaterialResource * ShaderMaterialResource,video::IRender * CurrentRender)
			{
				ShaderMaterialResource->AddUsage();
				ShaderMaterialResourceName = ShaderMaterialResource->GetName();

				core::IBuffer * ShaderMaterialBuffer = ShaderMaterialResource->GetShaderMaterial();
				ShaderMaterialBuffer->Lock(core::BLT_READ);
				c8 * ShaderMaterialSourceTemp = NULL;
				JENEW_A(ShaderMaterialSourceTemp,c8,ShaderMaterialBuffer->GetSize()+1)
				memset(ShaderMaterialSourceTemp,0,ShaderMaterialBuffer->GetSize()+1);
				ShaderMaterialBuffer->SetPosition(0);
				ShaderMaterialBuffer->Read(ShaderMaterialSourceTemp,ShaderMaterialBuffer->GetSize());
				ShaderMaterialBuffer->UnLock();
				jeStringc ShaderMaterialSource(ShaderMaterialSourceTemp);
				JEDELETE_A(ShaderMaterialSourceTemp)

				ShaderMaterial = CurrentRender->CreateShaderMaterial(ShaderMaterialSource);

				ShaderMaterialResource->RemoveUsage();
			}

			//! Destructor
			~jeSharedShaderMaterial()
			{
				ShaderMaterial->Drop();
			}

			//! Get Resource Name
			const jeStringc & GetResourceName()
			{
				return ShaderMaterialResourceName;
			}

			//! Get Shader Material
			video::IShaderMaterial * GetShaderMaterial()
			{
				return ShaderMaterial;
			}
		};
	}
}

#define JE_SHADERMATERIALRESOURCE( __Name ) JE_RESOURCEBASE_GET(__Name,ShaderMaterialResource)

#define JE_SHADERMATERIALRESOURCE_GRAB( __Var, __Res, __Key, __Render ) JE_RESOURCEBASE_SHARED_GRAB(__Var,__Res,__Key,__Render,ShaderMaterial)
#define JE_SHADERMATERIALRESOURCE_DROP( __Var, __Key, __Render) JE_RESOURCEBASE_SHARED_DROP(__Var,__Key,ShaderMaterialResource)

#define JE_SHADERMATERIALRESOURCE_SHARED_GRAB( __Var, __Res, __Render ) JE_SHADERMATERIALRESOURCE_GRAB(__Var,__Res,__Render->GetContext(),__Render)
#define JE_SHADERMATERIALRESOURCE_SHARED_DROP( __Var, __Render) JE_SHADERMATERIALRESOURCE_DROP(__Var,__Render->GetContext(),__Render)

#endif
